package clientHandle;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.ArrayList;

import roomAlgorithm.RoomGame;
//import roomAlgorithm.message;
import message.message;
import main.Main;
import main.Room;


public class HandleFromClient implements Runnable{

	private Socket socket = null;
	private ObjectOutputStream aObjectOS = null;
	private ObjectInputStream aObjectIS = null;
	
	private InputStreamReader input = null;
	private BufferedReader bufIn = null;
	private OutputStream out = null;
	
	private ArrayList<Room> roomList = null;
	private static final String ROOMID_FORMAT = "000000";
	private static final String USERID_FORMAT = "00000000";
	
	public static String flag[] = {""};
	public boolean isPlayingGame = false;

	public HandleFromClient(Socket socket) {
		this.socket = socket;
	}
	
	public Socket getSocket() {
		return socket;
	}
	
	public void run() {
		try {
			input = new InputStreamReader(socket.getInputStream(), "utf8");
			bufIn = new BufferedReader(input);
			String instruction = "";
			String response = "";
			
			
			aObjectOS = new ObjectOutputStream(socket.getOutputStream());
			aObjectIS = new ObjectInputStream(socket.getInputStream());
			message msg;
			
			
			msg = new message();
			msg = (message) aObjectIS.readObject();
			//ClientMessage msg = new ClientMessage();
			//msg = (ClientMessage) aObjectIS.readObject();
			
			System.out.println("Message from client:(String) " + msg.getString());
			instruction = msg.getString();
			System.out.println("Message from client:(Flag) " + msg.getFlag());
			
			
			//instruction = bufIn.readLine();
			//handle the instruction
			while(!instruction.equalsIgnoreCase("end")) {
				//login
				if (msg.getFlag()==0){
					response = userLogin(msg.getUsername(), msg.getPassword());
					//msg.setFlag(-1);
				}
				//sign up
				else if (msg.getFlag()==1){
					response = newUser(msg.getUsername(), msg.getPassword());
					//msg.setFlag(-1);
				}
				//other situations
				else{
					response = processInstruction(instruction);
				}
				if (instruction.equalsIgnoreCase("AFRL")){
					String[] responses = response.split(",");
					msg.setString(responses[0]);
					//msg.setFlag(Integer.parseInt(responses[1]));
				}
				else {
					msg.setString(response);
				}
				msg.setPlaying(false);
				aObjectOS.writeObject(msg); 
				//msg.setFlag(-1);
				
				if (isPlayingGame){
					System.out.println("thread is waiting...");	
					String gameFinishFlag = response.substring(0, 6)+"finish";
					synchronized (flag) {  
						while (!flag[0].equals(gameFinishFlag)) {  
							try {flag.wait();} catch (InterruptedException e) {e.printStackTrace();} 	                    
		                }
		            }
					System.out.println("Remove room...");
					for (int i=0; i<roomList.size(); i++){
						//System.out.println(roomList.get(i).getRoomID()+" "+gameFinishFlag);
						if (roomList.get(i).getRoomID().equalsIgnoreCase(gameFinishFlag.substring(0,6))){
							roomList.remove(i);
							System.out.println("... success!");
							break;
						}
					}
					
				}
				isPlayingGame = false;
				System.out.println("waiting for new msg");
				msg = (message) aObjectIS.readObject();
				instruction = msg.getString();
				System.out.println("Message from client(String): " + msg.getString());
				System.out.println("Message from client(Flag): " + msg.getFlag());
				//msg.setString("OK");
				//aObjectOS.writeObject(msg); 
				
				//out=socket.getOutputStream();
				//out.write(response.getBytes());
				/*
				OutputStreamWriter output = new OutputStreamWriter(socket.getOutputStream(),
						"utf8");
				BufferedWriter bufOut = new BufferedWriter(output);
				bufOut.write(response + "\r\n");
				bufOut.flush();
				instruction = bufIn.readLine();
				*/
			}
			//send feedback to the client
			//out=socket.getOutputStream();
			//out.write(response.getBytes());
			
			input.close();
			bufIn.close();
			//socket.close();
			System.out.println("Finish!Socket close");
			
				
			
		}
		catch(Exception ex) {
			System.out.println("One Client is closed!");
			ex.printStackTrace();
		} 
	}
	
	/**
	 * Handle the instruction
	 * @param instruction
	 * @throws IOException 
	 */
	public String processInstruction(String instruction){
		System.out.println("HandleFromClient: " + instruction);
		
		if(instruction == null || instruction.equals("")) {
			System.out.println("No Instruction!");
			return "No Instruction";
		}
		/*
		//new user
		else if (instruction.equals("NU")){
			String username = "";
			String password = "";
			if (Main.getDbAPI().newUser(username, password)){
				System.out.println("Server: new user create successfully!");
				Main.getDbAPI().printRecords();
				
			}else{
				System.out.println("Server: new user create failly!");
			}
		}
		
		//check valid user or not
		else if (instruction.equals("VU")){
			String username = "";
			String password = "";
			if (Main.getDbAPI().checkValid(username, password)){
				System.out.println("Server: user "+username+" is valid!");
				
			}else{
				System.out.println("Server: user "+username+" is NOT valid!");
			}
		}
		*/
		// client asks for room list
		else if (instruction.equalsIgnoreCase("AFRL")){
			//return room list
			String roomListInfo = "";
			roomList = Main.roomList;
			
			for (int i = 0; i < roomList.size(); i++){
				//get 16 bits room information for each room: roomID(6)+userID(8)+currentuseramount(2)
				roomListInfo += roomList.get(i).getRoomInfo();
			}
			System.out.println("Room list Info: "+roomListInfo);
			return roomListInfo+","+roomList.size();
		}
		
		// client creates a new room, instruction = userID (8)
		else if (instruction.length() == 8){
			//create a new room
			String roomID = getNewRoomID();
			System.out.println("Generate New Room ID: " + roomID);
			Room newRoom = new Room(roomID, instruction);
			newRoom.addClient(instruction);
			newRoom.addClientSocket(socket, aObjectIS, aObjectOS);
			Main.roomList.add(newRoom);
			isPlayingGame = true;
			flag[0]=roomID;
			return roomID;
		}
		
		// client entries an existed room, instruction = roomID(6) + userID (8) 
		else if (instruction.length() == 14){
			String roomID = instruction.substring(0, 6);
			String userID = instruction.substring(6);
			roomList = Main.roomList;
			//find designed room
			for (int i = 0; i < roomList.size(); i++){
				if (roomList.get(i).getRoomID().equals(roomID)){
					roomList.get(i).addClient(userID);
					roomList.get(i).addClientSocket(socket, aObjectIS, aObjectOS);
					System.out.println("User "+userID+" joined Room: "+roomID);
					Main.roomList = roomList;
					
					if (roomList.get(i).getCurrentUserAmount() == 3){
						//throw a RoomGame Thread
						RoomGame createRoom = new RoomGame(roomList.get(i));
						Thread roomGame = new Thread(createRoom);
						roomGame.start();
					}
					flag[0]=roomID;
					isPlayingGame = true;
					return roomList.get(i).getRoomInfo();
				}	
			}
			System.out.println("User "+userID+" failed to join Room: "+roomID);
			return "unsucessful";
		}
		
		return instruction;
	}
	
	public String getNewRoomID(){
		DecimalFormat df = new DecimalFormat(ROOMID_FORMAT);
		roomList = Main.roomList;
		for (int i = 0; i < roomList.size(); i++){
			if (Integer.parseInt(roomList.get(i).getRoomID()) != i){
			    return df.format(i);
			}	
		}
	    return df.format(roomList.size());
	}

	public String userLogin(String username, String password){
		String userID = "";
		String winRate = "";
		if (Main.getDbAPI().checkValid(username, password)){
			System.out.println("Server: user "+username+" is valid!");
			userID = Main.getDbAPI().getUserID(username, password);
		}else{
			System.out.println("Server: user "+username+" is NOT valid!");
		}
		
		if (!userID.equals("")){
			winRate += "Played: "+Main.getDbAPI().getPlayed(Integer.parseInt(userID))+" Won: "+Main.getDbAPI().getWon(Integer.parseInt(userID));
			DecimalFormat df = new DecimalFormat(USERID_FORMAT);
			userID = df.format(Integer.parseInt(userID));
		}
		//System.out.println("!!!!!!"+userID+winRate);
		return userID+winRate;
	}
	
	public String newUser(String username, String password){
		String userID = "";
		if (Main.getDbAPI().newUser(username, password)){
			System.out.println("Server: new user create successfully!");
			Main.getDbAPI().printRecords();
			userID = Main.getDbAPI().getUserID(username, password);
		}else{
			System.out.println("Server: new user create failly!");
		}
		
		if (!userID.equals("")){
			DecimalFormat df = new DecimalFormat(USERID_FORMAT);
			userID = df.format(Integer.parseInt(userID));
		}
		return userID;
	}
}
